#!/usr/bin/env python
"""
Nagios plugin that checks the overal usage of the grid pool accounts.
The plugin reports as a performance measurement, the number and ratio of the pool
account that with the highest usage pattern. (I.e. if there are various pool accounts,
the plugin only reports on the max used one.)

Performance metric: max_pool=ratio(used/available)%;warn;crit

-c : critical pool usage threshold. Ratio range [ 0.0 - 1.0] (0.9 default)
-w : warning pool usage threshold. Ratio range in [0.0 - 1.0] (0.7 default)

(no check whether c values <= w values)

"""
# last change: removed with_statement impl. due to backwards compatibility

__author__ = "Placi Flury grid@switch.ch"
__copyright__ = "Copyright 2010, SMSCG an AAA/SWITCH project"
__date__ = "19.05.2010"
__version__ = "0.3.0"


import sys, os.path
from nagios_plugin import NagiosPluginBasic, RETURN_CODE
from arc_conf_parser import *
import time


class GridPoolAccounts(NagiosPluginBasic):
    """ Probing of enabled pools of grid user accounts. The plugin
        returns the usage of each individual pool. The ratio of the 
        maximally used pool is reported as performance data.
    """
    def __init__(self):
        NagiosPluginBasic.__init__(self)
        self.options = None
        self.getOptions()
        try:
            self.parser = ARC_Parser(self.options.arc_conf)
            self.parser.main() # some init + sanity checking
        except ParseError, e1:
            print "Error: %s" % e1.message
            sys.exit(RETURN_CODE["error"])
        except SanityError, e2:
            print "Error: %s" % e2.message
            sys.exit(RETURN_CODE["error"])
        
    def _linecount(self, fname):
        """ private method to count lines of a file. """    
        n = 0 
        try:
            f= open(fname, 'r')
            for i, l in enumerate(f):
                pass
            n= i+ 1
        finally:
            f.close()
            return n
    
    def getOptions(self):
        """ command-line options parser """
        parser = NagiosPluginBasic.getOptions(self)
        parser.remove_option("-H") # remove hostname option
        parser.add_option("", "--arc_conf", action="store",
                    dest="arc_conf", default="/etc/arc.conf",
                    help="Location of the arc.conf file. (default:%default)")
        parser.add_option("-r", "--recycle_off", action="store_false",
                    dest="recycle", default=True,
                    help="Correct measurement if pool account recycling is turned off.")
        parser.add_option("-t", "--lifetime", action="store", type="int",
                    dest="mod_time_delta_days", default=10,
                    help="Time after which pool accounts will be recycled. (default:%default)")

        self.options = parser.parse_args()[0]
        
        if not self.options.critical_thresh:
            self.options.critical_thresh = 0.90 # 90 percent usage 
        if not self.options.warn_thresh:
            self.options.warn_thresh = 0.70 # 70 percent usage
    

    def get_pool_usage(self):
        """ probe for enabled pool accounts and their current usage. """

        grp2pooldir = self.parser.get_group2pooldir_map()
        grp2vo = self.parser.get_group2vo_map()
       
        vo_pool_usage = dict() 
        max_ratio = 0
 
        for grp, pool_dir in grp2pooldir.items():
            vo = grp2vo[grp]
            pool_file = os.path.join(pool_dir, 'pool')
            if os.path.exists(pool_file) and os.path.isfile(pool_file):
                pool_size = self._linecount(pool_file)

            files = os.listdir(pool_dir)
            num_used = 0
            num_recyclable = 0
            mod_time_delta_secs = 24 * 3600 * self.options.mod_time_delta_days
            for f in files:
                if f.startswith('_'): # assumption pool_files start with '_'
                    num_used += 1
                    mod_time = os.stat(pool_dir + '/' + f).st_mtime
                    if time.time() - mod_time > mod_time_delta_secs:
                        num_recyclable += 1
            if self.options.recycle:
                ratio = (num_used - num_recyclable) /float(pool_size)
                vo_pool_usage[vo] = ((num_used - num_recyclable), pool_size, ratio)
            else:
                ratio = num_used /float(pool_size)
                vo_pool_usage[vo] = (num_used, pool_size, ratio)
            if ratio > max_ratio: 
                max_ratio = ratio
        msg = '' 
        for pool, values in  vo_pool_usage.items():
            msg += "%s=%d/%d pools (%0.2f%%); " \
                % (pool, values[0], values[1], values[2]*100)
        perfdata = "pool_max=%0.2f;%0.2f;%0.2f" % \
            (max_ratio, self.options.warn_thresh, self.options.critical_thresh)
        
        if (max_ratio >= self.options.critical_thresh):
            print "CRITICAL: %s|%s" % (msg, perfdata)
            sys.exit(RETURN_CODE["critical"])

        if (max_ratio >= self.options.warn_thresh):
            print "WARNING: %s|%s" % (msg, perfdata)
            sys.exit(RETURN_CODE["warning"])

        # else, everything is fine
        print "OK: %s|%s" % (msg, perfdata)
        sys.exit(RETURN_CODE["ok"])
 

if __name__ == "__main__":
    gp = GridPoolAccounts()
    gp.get_pool_usage()


